package com.aliyun.messagemgt.application.service.Impl;

import com.aliyun.messagemgt.application.service.PushChannelMap;
import com.aliyun.messagemgt.common.annotation.PagingAnnotation;
import com.aliyun.messagemgt.common.dto.send.MsgPushDTO;
import com.aliyun.messagemgt.common.dto.send.MsgRecordVO;
import com.aliyun.messagemgt.common.dto.send.PushChannelInfo;
import com.aliyun.messagemgt.common.enums.ChannelTypeEnum;
import com.aliyun.messagemgt.converter.MessageRecordConverter;
import com.aliyun.messagemgt.converter.MsgHandleLogConverter;
import com.aliyun.messagemgt.domain.repository.MsgRecordRepository;
import com.aliyun.messagemgt.dto.MessageRecord;
import com.aliyun.messagemgt.dto.MsgHandleLog;
import com.aliyun.messagemgt.dto.in.ApiStatisticsQuery;
import com.aliyun.messagemgt.dto.msg.MessageRecordDTO;
import com.aliyun.messagemgt.dto.msg.MessageRecordQry;
import com.aliyun.messagemgt.dto.msg.ReceiverDTO;
import com.aliyun.messagemgt.dto.query.MsgPushResultsQuery;
import com.aliyun.messagemgt.dto.query.MyMsgQueryDTO;
import com.aliyun.messagemgt.dto.vo.MessageRecordQueryVO;
import com.aliyun.messagemgt.dto.vo.MessageRecordReturnVO;
import com.aliyun.messagemgt.dto.vo.MsgPushResultsQueryVO;
import com.aliyun.messagemgt.dto.vo.MsgRecordStatisticsVO;
import com.aliyun.messagemgt.dto.vo.MyMsgVO;
import com.aliyun.messagemgt.entities.MessageRecordEntity;
import com.aliyun.messagemgt.entities.MsgHandleLogEntity;
import com.aliyun.messagemgt.repository.mappers.MessageRecordMapper;
import com.aliyun.messagemgt.repository.mappers.MsgHandleLogMapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @Description
 * @Author hzw
 * @Date 2020/12/16 16:31
 * @Version 1.0
 */
@SuppressWarnings("ALL")
@Service
public class MsgRecordMybatisRepository implements MsgRecordRepository {
    private Logger logger = LoggerFactory.getLogger(MessageRecordServiceImpl.class);

    private static final String DAY_START = " 00:00:00";

    private static final String DAY_END = " 23:59:59";

    private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    @Value("${minusMonths.number}")
    private int minusMonthsNumber;
    @Value("${minusDays.number}")
    private int minusDaysNumber;
    @Value("${dev.source.prefix}")
    private String devSourcePrefix;
    @Autowired
    private MessageRecordMapper messageRecordMapper;

    @Autowired
    private MsgHandleLogMapper msgHandleLogMapper;

    @Autowired
    private PushChannelMap pushChannelMap;
    /**
     * 获取推送信息
     *
     * @param messageRecordQueryVO
     * @return
     */
    @Override
    public Page<MessageRecordReturnVO> selectMessageRecord(MessageRecordQueryVO messageRecordQueryVO) {
        return messageRecordMapper.selectMessageRecord(messageRecordQueryVO);
    }

    /**
     * 获取我的消息
     *
     * @param myMsgQueryDTO
     * @return
     */
    @Override
    public Page<MyMsgVO> selectMyMessageRecord(MyMsgQueryDTO myMsgQueryDTO) {
        return messageRecordMapper.selectMyMessageRecord(myMsgQueryDTO);
    }

    /**
     * 对外接口：消息查询
     *
     * @param msgPushResultsQuery
     * @return
     */
    @Override
    public Page<MsgPushResultsQueryVO> selectMsgPushResults(MsgPushResultsQuery msgPushResultsQuery) {
        return messageRecordMapper.selectMsgPushResults(msgPushResultsQuery);
    }

    /**
     * 查询历史消息
     *
     * @param historyDay
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Override
    public List<MessageRecord> queryMessageHistory(LocalDate historyDay, int pageNum, int pageSize) {
        List<MessageRecordEntity> messageRecordEntityList = messageRecordMapper.queryMessageHistory(historyDay, pageNum, pageSize);
        List<MessageRecord> messageRecordList = MessageRecordConverter.INSTANCE.messageRecordEntityList2messageRecordList(messageRecordEntityList);
        return messageRecordList;
    }

    /**
     * 查询DEV历史消息
     *
     * @param historyDay
     * @param sourceName
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Override
    public List<MessageRecord> queryDevMessageHistory(LocalDate historyDay, String sourceName, int pageNum, int pageSize) {
        List<MessageRecordEntity> messageRecordEntityList = messageRecordMapper.queryDevMessageHistory(historyDay, sourceName, pageNum, pageSize);
        List<MessageRecord> messageRecordList = MessageRecordConverter.INSTANCE.messageRecordEntityList2messageRecordList(messageRecordEntityList);
        return messageRecordList;
    }

    /**
     * 删除消息记录表数据
     *
     * @param msgList
     * @return
     */
    @Override
    public int deleteMsg(List<MessageRecord> msgList) {
        return messageRecordMapper.deleteMsg(msgList);
    }

    @Override
    public Long countMessageRecord(MessageRecordQueryVO messageRecordQueryVO) {
        return messageRecordMapper.countMessageRecord(messageRecordQueryVO);
    }

    /**
     * 消息归档--
     */
    //@Scheduled(cron = "0 30 2 * * ?")
    @SuppressWarnings("unchecked")
    @Override
    public void messageArchive(){
        LocalDate now = LocalDate.now();
        LocalDate yesterday = now.minusDays(1);
        //定时任务搬迁月份有2个月前改为一个月前
        LocalDate historyDay = yesterday.minusMonths(minusMonthsNumber);
        boolean devIfNull = true;
        boolean ifNull = true;
        int pageNum = 0;
        int pageSize = 1000;
        //先搬迁DEV的数据
        while (devIfNull){
            LocalDate historyDevDay = now.minusDays(minusDaysNumber);
            List<MessageRecordEntity> messageRecordEntityList = messageRecordMapper.queryDevMessageHistory(historyDevDay,devSourcePrefix,pageNum,pageSize);
            List<MessageRecord> msgList = MessageRecordConverter.INSTANCE.messageRecordEntityList2messageRecordList(messageRecordEntityList);
            logger.info("dev消息记录表查询结果 {}",msgList);
            pageNum = pageNum+pageSize;
            if (CollectionUtils.isEmpty(msgList)){
                ifNull = false;
                dealDevMsgLog(historyDevDay,0,1000);
                break;
            }else {
                //插入历史表
                /*int i = messageRecordMapper.insertHis(msgList);
                if (i>0){
                    //删除消息记录中中数据
                    messageRecordMapper.deleteMsg(msgList);
                }*/
            }
        }
        //搬迁正式数据
        while (ifNull){
            List<MessageRecordEntity> messageRecordEntityList = messageRecordMapper.queryMessageHistory(historyDay,pageNum,pageSize);
            List<MessageRecord> msgList = MessageRecordConverter.INSTANCE.messageRecordEntityList2messageRecordList(messageRecordEntityList);
            logger.info("消息记录表查询结果 {}",msgList);
            pageNum = pageNum+pageSize;
            if (CollectionUtils.isEmpty(msgList)){
                ifNull = false;
                dealMsgLog(historyDay,0,1000);
                break;
            }else {
                //插入历史表
                /*int i = messageRecordMapper.insertHis(msgList);
                if (i>0){
                    //删除消息记录中中数据
                    messageRecordMapper.deleteMsg(msgList);
                }*/
            }
        }

    }
    private void dealMsgLog(LocalDate historyDay, int pageNum, int pageSize) {
        while (true){
            List<MsgHandleLogEntity> msgHandleLogEntityList = msgHandleLogMapper.queryHistoryMsg(historyDay, pageNum, pageSize);
            List<MsgHandleLog> msgHandleLogs = MsgHandleLogConverter.INSTANCE.msgHandleLogEntityList2msgHandleLogList(msgHandleLogEntityList);
            logger.info("消息记录表查询结果 {}",msgHandleLogs);
            pageNum = pageNum+pageSize;
            if (CollectionUtils.isEmpty(msgHandleLogs)){
                break;
            }else {
                //插入历史表
               /* int i = msgHandleLogMapper.insertHistoryMsg(msgHandleLogs);
                if (i>0){
                    //删除消息记录中中数据
                    msgHandleLogMapper.deleteHistoryMsg(msgHandleLogs);
                }*/
            }
        }
    }

    private void dealDevMsgLog(LocalDate historyDevDay, int pageNum, int pageSize) {
        while (true){
            List<MsgHandleLogEntity> msgHandleLogEntityList = msgHandleLogMapper.queryDevHistoryMsg(historyDevDay,devSourcePrefix, pageNum, pageSize);
            List<MsgHandleLog> msgHandleLogs = MsgHandleLogConverter.INSTANCE.msgHandleLogEntityList2msgHandleLogList(msgHandleLogEntityList);
            logger.info("dev消息记录表查询结果 {}",msgHandleLogs);
            pageNum = pageNum+pageSize;
            if (CollectionUtils.isEmpty(msgHandleLogs)){
                break;
            }else {
                //插入历史表
               /* int i = msgHandleLogMapper.insertHistoryMsg(msgHandleLogs);
                if (i>0){
                    //删除消息记录中中数据
                    msgHandleLogMapper.deleteHistoryMsg(msgHandleLogs);
                }*/
            }
        }
    }

    @Override
    public int batchMsgRecordInsert(List<MsgRecordVO> msgRecordVos) {
        return messageRecordMapper.batchMsgRecordInsert(msgRecordVos);
    }

    @Override
    public List<MsgRecordStatisticsVO> queryMsgRecordsStatistics(ApiStatisticsQuery apiStatisticsQuery) {
        return messageRecordMapper.queryMsgRecordsStatistics(apiStatisticsQuery);
    }

    @Override
    @PagingAnnotation
    public PageInfo<MessageRecordDTO> page(MessageRecordQry messageRecordQry) {
        PageHelper.orderBy("mr.msg_id desc");
        List<MessageRecordEntity> messageRecordEntityList = messageRecordMapper.page(messageRecordQry);
        PageInfo<MessageRecordEntity> messageRecordEntityPageInfo = new PageInfo(messageRecordEntityList);
        PageInfo<MessageRecordDTO> messageRecordDTOPageInfo = MessageRecordConverter.INSTANCE.messageRecordEntityPageInfo2messageRecordDTOPageInfo(messageRecordEntityPageInfo);
        List<MessageRecordDTO> messageRecordDTOList = messageRecordDTOPageInfo.getList();
        if(CollectionUtils.isNotEmpty(messageRecordDTOList)){
            List<Long> msgIdList = messageRecordDTOList.stream().map(MessageRecordDTO::getMsgId).collect(Collectors.toList());
            List<MsgHandleLogEntity> msgHandleLogEntityList = msgHandleLogMapper.queryByMsgIdList(msgIdList);
            Map<Long, List<MsgHandleLogEntity>> msgHandleLogEntityMap = msgHandleLogEntityList.stream().collect(Collectors.groupingBy(MsgHandleLogEntity::getMsgId));
            messageRecordDTOList.stream().forEach(
                    messageRecordDTO -> {
                        String pushChannelTypes = messageRecordDTO.getPushChannelType();
                        if(StringUtils.isNotBlank(pushChannelTypes)){
                            StringBuilder sb = new StringBuilder();
                            Arrays.stream(pushChannelTypes.split(",")).forEach(
                                    pushChannelTypeStr -> {
                                        String pushChannelTypeName = ChannelTypeEnum.getName(Integer.valueOf(pushChannelTypeStr));
                                        sb.append(pushChannelTypeName).append(",");
                                    }
                            );
                        messageRecordDTO.setPushChannelTypeName(sb.substring(0,sb.length()-1));
                        }
                        Long msgId = messageRecordDTO.getMsgId();
                        List<MsgHandleLogEntity> msgHandleLogEntitys = msgHandleLogEntityMap.get(msgId);
                        List<ReceiverDTO> receiverDTOList = MsgHandleLogConverter.INSTANCE.msgHandleLogEntitys2receiverDTOList(msgHandleLogEntitys);
                        messageRecordDTO.setReceiverDTOList(receiverDTOList);
                    }
            );

        }
        return messageRecordDTOPageInfo;
    }

    @Override
    public void updateMsgRecordStatus(MsgRecordVO msgRecordVO) {
        messageRecordMapper.updateMsgRecordStatus(msgRecordVO);
    }

    @Override
    public List<MsgRecordVO> getMsgRecordVOList(Long msgId) {
        MessageRecordEntity messageRecord = messageRecordMapper.getOne(msgId);
        // 1.查询发送失败的用户日志
        List<MsgHandleLogEntity> msgHandleLogEntityList = msgHandleLogMapper.queryFailedByMsgId(msgId);
        // 2.按渠道分组msgHandleLogEntityList
        Map<Long, List<MsgHandleLogEntity>> msgHandleLogEntityMap = msgHandleLogEntityList.stream().filter(obj -> Objects.nonNull(obj.getPushChannelId()))
                .collect(Collectors.groupingBy(MsgHandleLogEntity::getPushChannelId));
        List<MsgRecordVO> msgRecordVOList = new ArrayList<>();
        msgHandleLogEntityMap.entrySet().stream().forEach(
                entity -> {
                    // 3.再按接收者类型分组ReceiveRangeInfo，构造不同渠道的msgRecordVO用于消息重发
                    List<MsgRecordVO> msgRecordVOS = processMsgHandleLogEntity(entity, messageRecord);
                    msgRecordVOList.addAll(msgRecordVOS);
                }
        );
        return msgRecordVOList;
    }

    private List<MsgRecordVO> processMsgHandleLogEntity(Map.Entry<Long, List<MsgHandleLogEntity>> entity, MessageRecordEntity messageRecord) {
        Long pushChannelId = entity.getKey();
        List<MsgHandleLogEntity> msgHandleLogEntityList = entity.getValue();
        List<PushChannelInfo> pushChannelInfoList = new ArrayList<>();
        PushChannelInfo pushChannelInfo = pushChannelMap.getChannelInfoByChannelId(pushChannelId);
        pushChannelInfoList.add(pushChannelInfo);
        List<String> pushChannelCodes = new ArrayList<>();
        pushChannelCodes.add(pushChannelInfo.getChannelCode());
        List<MsgRecordVO> msgRecordVOList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(msgHandleLogEntityList)) {
            Map<String, List<MsgHandleLogEntity>> msgHandleLogEntityMap = msgHandleLogEntityList.stream().collect(Collectors.groupingBy(MsgHandleLogEntity::getReceiverType));
            msgHandleLogEntityMap.entrySet().stream().forEach(
                    receiveEntity -> {
                        String rangeType = receiveEntity.getKey();
                        List<MsgHandleLogEntity> msgHandleLogEntitys = receiveEntity.getValue();
                        List<String> rangeValues = msgHandleLogEntitys.stream().map(MsgHandleLogEntity::getReceiverId).collect(Collectors.toList());
                        MsgPushDTO.MsgRecordDTO.ReceiveRangeInfo receiveRangeInfo = new MsgPushDTO.MsgRecordDTO.ReceiveRangeInfo();
                        receiveRangeInfo.setRangeTransType("CUST");
                        receiveRangeInfo.setRangeType(rangeType);
                        receiveRangeInfo.setRangeValues(rangeValues);
                        MsgRecordVO msgRecordVO = MessageRecordConverter.INSTANCE.messageRecord2msgRecordVO(messageRecord);
                        // 设置渠道id，方便后续发送成功后基于此条件更新状态
                        msgRecordVO.setPushChannelId(pushChannelId.toString());
                        msgRecordVO.setReceiveChannelCodes(pushChannelCodes);
                        msgRecordVO.setPushChannelInfoList(pushChannelInfoList);
                        msgRecordVO.setReceiveRangeInfo(receiveRangeInfo);
                        // 手动重发，使用默认重试次数、重试时间间隔
                        msgRecordVO.setFailureResendTimes(1);
                        msgRecordVO.setFailureResendInterval(1);
                        msgRecordVOList.add(msgRecordVO);
                    }
            );
        }
        return msgRecordVOList;
    }
}
